#pragma once

#include <tshark_manager.h>
#include <tshark_error.h>
#include <loguru/loguru.hpp>
#include <httplib.h>

/*
    note: Controller套路
    观察PacketController中的getPacketList函数，可以发现，作为一个接口响应函数,有一定的套路：
        1、提取参数（父类提供，子类可以重载）
        2、真正干活（具体的数据处理逻辑，比如从数据库提取出文件进行处理等，然后进行序列化，由子类负责）
        3、返回响应（将序列化后的数据交给客户端，基本不会改变，由父类处理）
        4、还有异常处理（基本不会修改，由父类提供）
    可以把这些共通的逻辑提取出来，封装起来，每个接口就只干独属于自己接口里面的逻辑，就不用写这么多重复的代码了
 */
namespace Controller
{
    class BaseController
    {
    public:
        BaseController(std::shared_ptr<httplib::Server> server,std::shared_ptr<Tshark::TsharkManager> tsharkManager);
        virtual ~BaseController() = default;

        // 由子类实现
        virtual void registerRoute() = 0;

    protected:
        std::shared_ptr<Tshark::TsharkManager> m_tsharkManager;
        std::shared_ptr<httplib::Server> m_server;

    public:
        // 从URL中提取整数参数(应该是get请求使用)
        static int getIntParam(const httplib::Request &req, std::string paramName, int defaultValue = 0);

        // 从URL中提取字符串参数(应该是get请求使用)
        static std::string getStringParam(const httplib::Request &req, const std::string &paramName, const std::string &defaultValue = 0);

    protected:
        // 请求成功且数据不为空，返回数据列表
        template <typename Data>
        void sendDataList(httplib::Response &resp, std::vector<std::shared_ptr<Data>> &dataList);

        /// @brief 成功响应,返回json内容
        /// @param resp 
        /// @param data 
        void sendResponJson(httplib::Response& resp,Json::Value& data);

        // 返回成功响应，但是没有数据
        void sendSuccessResponse(httplib::Response &resp);

        // 发送错误响应
        void sendErrorResponse(httplib::Response &resp, int errorCode);

        // 提取请求中的参数(应该是post请求使用)
        bool parseQueryCondition(const httplib::Request &req, Tshark::QueryConditon &condition);
    };

    template <typename Data>
    inline void BaseController::sendDataList(httplib::Response &resp, std::vector<std::shared_ptr<Data>> &dataList)
    {
        /**
         * 返回数据格式：
         * {
         *     "code": 0,
         *     "msg": "操作成功",
         *     "data" [] / {}
         * }
         */
        Json::Value respJson;
        respJson["msg"] = "操作成功";
        respJson["code"] = 0;
        Json::Value data;
        for (auto &dataPtr : dataList)
        {
            data.append(dataPtr->to_json());
        }
        respJson["data"] = data;
        // 序列化json
        Json::StreamWriterBuilder writerBuilder;
        const std::string respStr = Json::writeString(writerBuilder, respJson);
        resp.set_content(respStr,"application/json");
    }
}